package camera;

import javax.vecmath.Vector3d;

public abstract class Camera {
	 
	public double wfov;
	public double hfov;
	public double aspectRatio;
	public double fov;
	
	public Vector3d up;
	public Vector3d cameraVector;
	public Vector3d eye;
	public Vector3d forward;
	public Vector3d right;
	
	public Camera ( Vector3d eye, Vector3d target, Vector3d up, double fov, double aspectRatio) {
		if (eye == null || target == null || up == null) {
			throw new IllegalArgumentException("null arguments in Camera constructor");
		}
		
		this.forward = new Vector3d(target);
		this.forward.sub(eye);
		this.forward.normalize();
		
		this.up = new Vector3d();
		this.right = new Vector3d();
		this.eye = eye;
		this.aspectRatio = aspectRatio;

		this.fov = fov;
		this.wfov = Math.toRadians(fov);
		this.hfov = 2 * Math.atan(Math.tan(wfov/2) / aspectRatio);

		this.right.cross(forward, up);
		this.up.cross(this.forward, this.right);
		
		//this.up.cross(target, this.right);
		this.up.negate();
		this.forward.normalize();
		this.up.normalize();
		this.right.normalize();
	}
	
//	public Camera ( Vector3d eye, Vector3d target, Vector3d up, double fov, double aspectRatio) {
//		if (eye == null || target == null || up == null) {
//			throw new IllegalArgumentException("null arguments in Camera constructor");
//		}
//		
//		this.aspectRatio = aspectRatio;
//		this.fov = fov;
//		this.wfov = Math.toRadians(fov);
//		this.up = up;
//		this.eye = eye;
//		
//		//Sea aspectRatio = ancho / alto 	(Ej: 4:3)
//		//El hfov viene a ser el angulo que se forma entre la horizontal y los extremos superior e inferior del
//		//raster. Haciendo el analisis trigonometrico queda el siguente calculo (ver detalle en el informe)
//		this.hfov = 2 * Math.atan(Math.tan(wfov/2) / aspectRatio);
//		
//		this.forward = new Vector3d();
//		this.forward.sub(target, eye);
//		this.forward.normalize();
//		
//		//Se calcula tambien una referencia que es el vector "rightReference"
//		//cuyo valor es el producto cruzado entre forward y up
//		//Este mismo sirve para calcular los vectores tl, tr, bl y br.
//		this.right = new Vector3d();
//		right.cross(forward, up);
//		right.normalize();
//		
//	}

	public Vector3d TL_vector() {
		Vector3d tl = new Vector3d(forward);
		Vector3d dist_w = new Vector3d(right);
		Vector3d dist_h = new Vector3d(up);

		dist_w.scale(Math.tan(wfov/2));
		dist_h.scale(Math.tan(hfov/2));
		dist_w.negate();
		
		tl.add(dist_w);
		tl.add(dist_h);
		return tl;
	}
	
	public Vector3d TR_vector() {
		Vector3d tr = new Vector3d(forward);
		Vector3d dist_w = new Vector3d(right);
		Vector3d dist_h = new Vector3d(up);

		dist_w.scale(Math.tan(wfov/2));
		dist_h.scale(Math.tan(hfov/2));

		tr.add(dist_w);
		tr.add(dist_h);
		return tr;
	}

	public Vector3d BL_vector() {
		Vector3d bl = new Vector3d(forward);
		Vector3d dist_w = new Vector3d(right);
		Vector3d dist_h = new Vector3d(up);

		dist_w.scale(Math.tan(wfov/2));
		dist_h.scale(Math.tan(hfov/2));
		dist_w.negate();
		dist_h.negate();

		bl.add(dist_w);
		bl.add(dist_h);
		return bl;
	}
	
	public Vector3d BR_vector() {
		Vector3d br = new Vector3d(forward);
		Vector3d dist_w = new Vector3d(right);
		Vector3d dist_h = new Vector3d(up);
		
		dist_w.scale(Math.tan(wfov/2));
		dist_h.scale(Math.tan(hfov/2));
		dist_h.negate();

		br.add(dist_w);
		br.add(dist_h);
		return br;
	}
}
